#pragma region Description
/*
     Copyright © 2011 Jesse 'LorgonJortle' Wilkerson
     See licensing in source (.cpp) file, or at:
     <http://www.gnu.org/licenses/> (GPL)

     File: ShaderManager.h
     Author: Jesse 'LorgonJortle' Wilkerson
     Description:
          Not much can be rendered in OpenGL without the use
          of shaders. This class was designed to help with shader
          loading/compiling/linking/using. It comes with a handful
          of stock shaders, and it supports as many custom shaders
          as needed.
*/
#pragma endregion

#ifndef SHADERMANAGER_H
#define SHADERMANAGER_H

/*****************************************
                              OpenGL
*****************************************/
     #ifdef __APPLE__
         #include <glew.h>
     #else
         #include <GL/glew.h>
     #endif
/****************************************/

/*****************************************
                         Standard C++
*****************************************/
     #include <deque>
     #include <string>
     #include <iostream>
     #include <fstream>
     #include <algorithm>
/****************************************/

/*****************************************
                         LOGL::GLib
*****************************************/
     /*****************************************
                                   Utilities
     *****************************************/
          #include "Exception.h"
/****************************************/

namespace LOGL_GLib
{
     namespace Common
     {
          /* Shader attribute indices, as used by LOGL::GLib. */
          enum Attribute
          {
               Attribute_Position,
               Attribute_Color,
               Attribute_Normal,
               Attribute_Texture0,
               Attribute_Texture1,
               Attribute_Texture2,
               Attribute_Texture3,
               Attribute_Misc
          };

          /* The specific attributes that can be connected with a shader. */
          struct ShaderAttributes
          {
          public:
               /* Construct a ShaderAttributes object. */
               ShaderAttributes();

               /* Set the specified attribute's name as it appears in the shader program. */
               GLvoid SetAttribute(Attribute _Attribute, GLchar* _Name);

               /* The number of attributes that have been specified for the program. */
               GLint UsedAttributes;
               /* The list of attributes. */
               GLboolean Attributes[16];
               /* The names of the attributes with corresponding indices. */
               std::string AttributeNames[16];
               /* The resultant fragment color, as it appears in the fragment shader. */
               std::string FragmentAttribute;
          }; /* Struct ShaderAttributes. */

          /* The formats that the shader source can be loaded in. */
          enum ShaderFormat
          {
               FromFile,
               FromMemory
          }; /* Enum ShaderFormat. */

        /* The Shader class that is the base/parent for all other shaders. */
          class Shader
          {
               public:
                    /* Constructs a shader object. */
                    Shader();
                    /* Constructs a Shader object with the specified name. */
                    Shader(const std::string& _Name);
                     /* Destructs the shader object and release any indebted resources. */
                    ~Shader();

                    /* Loads the specified shader program. */
                    GLboolean Load(ShaderFormat _Format, const GLchar* _VertexFile, const GLchar* _GeometryFile, const GLchar* _FragmentFile);
                     /* Loads a vertex shader program from the specified fies. */
                    GLboolean LoadVertexProgram(ShaderFormat _Format, const GLchar* _VertexFile);
                     /* Loads a geometry shader program from the specified fies. */
                    GLboolean LoadGeometryProgram(ShaderFormat _Format, const GLchar* _VertexFile);
                     /* Loads a fragment shader program from the specified fies. */
                    GLboolean LoadFragmentProgram(ShaderFormat _Format, const GLchar* _VertexFile);
                     /* Loads the entire specified file and sets it as the program's source. */
                    GLboolean SourceFromFile(const std::string& _File, GLint _ShaderID);
                     /* Compiles and links the shader's source. */
                    GLboolean Compile();
                     /* Gets the location of the specified uniform in the currently bound program. */
                    GLint GetUniformLocation(const std::string& _Uniform);

                    /* The name of the shader. */
                    std::string Name;
                     /* The attributes of the shader. */
                    ShaderAttributes Attributes;

                 /* The OpenGL-given ID for the vertex shader. */
                    GLuint VertexProgramID;
                     /* The OpenGL-given ID for the geometry shader. */
                    GLuint GeometryProgramID;
                     /* The OpenGL-given ID for the fragment shader. */
                    GLuint FragmentProgramID;
                     /* The OpenGL-given ID for the shader program. */
                    GLuint ProgramID;
                     /* The ID that the game uses to access the shader. */
                    GLuint ID;

                 /* The compile log that will hold errors if they occur. */
                    GLchar Log[1024];

          }; /* Class Shader. */

        /* The ShaderManager class that maintains all loaded shaders in the game. */
          class ShaderManager
          {
               public:
                /* Constructs a ShaderManager. */
                    ShaderManager();

                /* Adds the specified shader to the manager. */
                    GLuint Add(Shader& _Shader);
                    /* Removes the specified shader from the manager. */
                    GLvoid Remove(GLuint _ShaderID);
                    /* Binds/Enables the specified (already loaded) shader program. */
                    GLboolean Bind(GLuint _ShaderID);
                    /* Unbinds any programs and returns to fixed-functionality. */
                    GLvoid Unbind() const;
                    /* Gets a pointer to the specified shader. */
                    Shader* const At(GLuint _ShaderID);

               private:
                /* The next shader's ID number (to avoid duplicates). */
                    GLint nextID;
                    /* The list of the currently loaded shaders. */
                    std::deque<Shader> shaders;

          }; /* Class ShaderManager. */

     } /* Namespace Common. */
} /* Namespace LOGL_GLib. */

#endif
